1. 题目
题目链接:P4462「[CQOI2018]异或序列」 。
题目描述
已知一个长度为n的整数数列 a1,a2,⋯,an,给定查询参数 l,r,问在 al,al+1,⋯,ar 区间内,有多少子序列满足异或和等于 k。也就是说,对于所有的 x,y(l≤x≤y≤r),能够满足 ax⨁ax+1⨁⋯⨁ay=k 的 x,y 有多少组。
输入格式
输入文件第一行,为 3 个整数 n,m,k。
第二行为空格分开的 n 个整数,即 a1,a2,..an。
接下来 m 行,每行两个整数 lj,rj,表示一次查询。
输出格式
输出文件共 m 行,对应每个查询的计算结果。
输入输出样例
输入 #1
1 2 3 4 5 6 7
   | 4 5 1 1 2 3 1 1 4 1 3 2 3 2 4 4 4
   | 
 
输出 #1
说明/提示
对于 30% 的数据,1≤n,m≤1000。
对于 100% 的数据,1≤n,m≤105,0≤k,ai≤105,1≤lj≤rj≤n。
2. 题解
分析
- 设 si=a1⨁a2⨁⋯⨁ai,则有
 
al⨁al+1⨁⋯⨁ar=sl−1⨁sr
- 假设 a⨁b=c,则有
 
a=b⨁cb=a⨁c
因此,对于原题,我们可以将其转换为:在区间 [l,r] 内,有多少对 sx−1,sy(l≤x≤y≤r)满足 sx−1⨁sy=k,其中,si=a1⨁⋯⨁ai−1,即 s 数组为 a 数组的异或前缀和。
- 然后计算一下时间复杂度,O(mn) 可以过,而且可以离线查询,因此可以考虑用莫队算法。接下的问题就是如何实现相邻查询区间的 O(1) 转移。
 
假设序列 s 的长度为 n,若已知 [l,r] 区间的答案为 ansl,r,且 count 数组记录了数组 s 在 [l,r] 区间中各个数的出现次数,则区间 [l,r+1](其它三个相邻区间的分析类似)的答案为
ansl,r+1=ansl,r+count[s[r+1]k]
因此,只要在区间改变时维护好 count 数组,就可实现相邻查询区间 O(1) 复杂度的转移。
注意
需要判断一下应该开的数组大小以及数据类型是否会溢出:
- 数组大小:由于 0≤k,ai≤105,因此它们之间的异或结果最大为 2⌊log2105⌋+1−1,即异或的结果会超出 105,但始终能用 ⌊log2105⌋ 位二进制表示。而 ⌊log2105⌋ 位二进制所能表示的最大数为 2⌊log2105⌋+1−1,又 2⌊log2105⌋+1−1≤2×105−1,因此数组长度需要开到 2×105 才合适。
 
- 数据类型:由于区间 [l,r] 中最多有 Cr−l+12 种两两配对,且 r−l+1≤105,因此 Cr−l+12<=5×104×(105−1)≈5×109,所以 
int 数据类型其实是不够用的,要用 long long。 
虽然这道没有卡这两点,但不可忽略它们。另一道基本相同的题 CF617E XOR and Favorite Number 就考虑了这两点。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
   | #include<bits/stdc++.h> using namespace std;
  #ifndef _MOBK_ #define _MOBK_ #define ll long long #define il inline #define re register #define MAXN 200100
  char buf[200];
  il ll read() {     ll x = 0;     char ch = getchar();     while(ch < '0' || ch > '9'){         ch = getchar();     }     while(ch >= '0' && ch <= '9') {         x = (x << 3) + (x << 1) + (ch ^ 48);         ch = getchar();     }     return x; }
  il void write(ll x) {     ll cnt = 0;     while(x || !cnt) {         buf[cnt++] = (x%10) + 48;         x /= 10;     }     while(cnt) {         putchar(buf[--cnt]);     }     putchar('\n'); }
 
  ll bz;
  struct MOBK {          struct Query {         ll l, r, idx;         bool operator < (const Query q) const {             return l/bz != q.l/bz ? l < q.l :                  (l/bz) & 1 ? r < q.r : r > q.r;         }     };     ll n, m;                 ll curans;               ll count[MAXN];          ll result[MAXN];         Query query[MAXN];            MOBK() {         curans = 0;         memset(count, 0, sizeof(count));         memset(query, 0, sizeof(query));     }     MOBK(int _n, int _m): n(_n), m(_m) {         bz = (ll)sqrt(n);         curans = 0;         memset(count, 0, sizeof(count));         memset(query, 0, sizeof(query));     }          il void add(ll x, ll k) {         curans += count[x^k];         ++count[x];     }          il void del(ll x, ll k) {         --count[x];         curans -= count[x^k];              }          void solver(ll *a, ll k) {         sort(query, query+m);         re ll l = query[0].l;         re ll r = query[0].l-1;         for(re ll i = 0; i < m; ++i) {             while(r < query[i].r) {                 add(a[++r], k);             }             while(r > query[i].r) {                 del(a[r--], k);             }             while(l < query[i].l) {                 del(a[l++], k);             }             while(l > query[i].l) {                 add(a[--l], k);             }             result[query[i].idx] = curans;         }         for(ll i = 0; i < m; ++i) {             write(result[i]);         }     } }; #endif
  int main() {     ll n = read();     ll m = read();     ll k = read();     static ll a[MAXN] = {0};     static MOBK mobk = MOBK(n, m);     for(re ll i = 1; i <= n; ++i) {         a[i] = read();     }     for(re ll i = 2; i <= n; ++i) {         a[i] ^= a[i-1];     }     for(re ll i = 0; i < m; ++i) {         mobk.query[i].l = read() - 1;         mobk.query[i].r = read();         mobk.query[i].idx = i;     }     mobk.solver(a, k);     return 0; }
   |